<?php

namespace App\Providers;

use App\User;
use Auth;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any application authentication / authorization services.
     *
     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
     * @return void
     */
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);

        Auth::viaRequest('sign', function ($request) {
            if ($request->input('_sign') or $request->input('sign')) {
                return $this->signVerify($request->all());
            }
        });
    }

    private function signVerify($params)
    {
        info('sign');
        $pass = array_pull($params, '_pass');
        $sign = array_pull($params, '_sign');
        $sign = $sign ?: array_pull($params, 'sign');
        if (!$sign) {
            return null;
        }
        $userName = data_get($params, '_partner');
        $userName = $userName ?: data_get($params, 'account');
        $userName = $userName ?: data_get($params, 'appid');
        $user = User::where('name', $userName)->first();

        if (!$user) {
            return null;
        }
        if (\App::environment('local') && $pass) {
            return $user;
        }

        ksort($params);
        foreach ($params as $key => $val) {
            $stringToSignV2[] = "$key=$val";
        }
        $stringToSignV2 = implode('&', $stringToSignV2) . $user->api_token;

        $appKeyDesensitized = substr($user->api_token, 0, 3) . '******' . substr($user->api_token, -3);
        $stringToSignDesensitized = http_build_query($params) . $appKeyDesensitized;
        $stringToSign = http_build_query($params) . $user->api_token;

        if (md5($stringToSign) == $sign or md5($stringToSignV2) == $sign) {
            return $user;
        } else {
            \Log::error('签名错误', [
                'string_v1' => $stringToSign, 'sign_v1' => md5($stringToSign),
                'string_v2' => $stringToSignV2, 'sign_v2' => md5($stringToSignV2), 'sign' => $sign
            ]);
            throw new \LogicException("签名错误", 1);
        }
    }
}
